#include "cacheupdatewidget.h"
#include "ui_cacheupdatewidget.h"

#include <QLabel>
#include <QListView>
#include <QProgressBar>
#include <QPushButton>
#include <QStandardItemModel>

#include <QIcon>
#include <QDebug>

#include <QApt/Transaction>

CacheUpdateWidget::CacheUpdateWidget(QWidget *parent) : QWidget(parent), ui(new Ui::CacheUpdateWidget), m_trans(0), m_lastRealProgress(0)
{
    ui->setupUi(this);

    m_headerLabel = ui->headerLabel;
    m_downloadView = ui->downloadView;
    m_downloadModel = new QStandardItemModel(this);
    m_downloadView->setModel(m_downloadModel);
    m_downloadSpeedLabel = ui->downloadSpeedLabel;
    m_ETALabel = ui->ETALabel;
    m_totalProgress = ui->totalProgress;
    m_cancelButton = ui->cancelButton;
}

CacheUpdateWidget::~CacheUpdateWidget()
{
    delete ui;
}

void CacheUpdateWidget::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void CacheUpdateWidget::clear()
{
    m_downloadModel->clear();
    m_downloads.clear();
    m_totalProgress->setValue(0);
}

void CacheUpdateWidget::setTransaction(QApt::Transaction *trans)
{
    m_trans = trans;
    clear();
    m_cancelButton->setEnabled(m_trans->isCancellable());
    connect(m_cancelButton, SIGNAL(pressed()), m_trans, SLOT(cancel()));

    // Listen for changes to the transaction
    connect(m_trans, SIGNAL(cancellableChanged(bool)), m_cancelButton, SLOT(setEnabled(bool)));
    connect(m_trans, SIGNAL(statusChanged(QApt::TransactionStatus)), this, SLOT(onTransactionStatusChanged(QApt::TransactionStatus)));
    connect(m_trans, SIGNAL(progressChanged(int)), this, SLOT(progressChanged(int)));
    connect(m_trans, SIGNAL(downloadProgressChanged(QApt::DownloadProgress)), this, SLOT(downloadProgressChanged(QApt::DownloadProgress)));
    connect(m_trans, SIGNAL(downloadSpeedChanged(quint64)), this, SLOT(updateDownloadSpeed(quint64)));
    connect(m_trans, SIGNAL(downloadETAChanged(quint64)), this, SLOT(updateETA(quint64)));
}

void CacheUpdateWidget::addItem(const QString &message)
{
    QStandardItem *n = new QStandardItem();
    n->setText(message);
    m_downloadModel->appendRow(n);
    m_downloadView->scrollTo(m_downloadModel->indexFromItem(n));
}

void CacheUpdateWidget::updateDownloadSpeed(quint64 speed)
{
    QString downloadSpeed = QString("Download rate: %1/s").arg(speed/1000.0);
    m_downloadSpeedLabel->setText(downloadSpeed);
}

void CacheUpdateWidget::updateETA(quint64 ETA)
{
    QString timeRemaining;
    int ETAMilliseconds = ETA * 1000;

    if (ETAMilliseconds <= 0 || ETAMilliseconds > 14*24*60*60*1000) {
        // If ETA is less than zero or bigger than 2 weeks
        timeRemaining = "Unknown time remaining";
    } else {
        timeRemaining = QString("%1 remaining").arg(ETAMilliseconds);
    }
    m_ETALabel->setText(timeRemaining);
}

void CacheUpdateWidget::onTransactionStatusChanged(QApt::TransactionStatus status)
{
    QString headerText;

    qDebug() << "cache widget: transaction status changed" << status;

    switch (status) {
    case QApt::DownloadingStatus:
        if (m_trans->role() == QApt::UpdateCacheRole)
            headerText = "<b>Updating software sources</b>";
        else
            headerText = "<b>Downloading Packages</b>";

        m_headerLabel->setText(headerText);
        break;
    default:
        break;
    }
}

void CacheUpdateWidget::progressChanged(int progress)
{
    if (progress > 100) {
        m_totalProgress->setMaximum(0);
    } else if (progress > m_lastRealProgress) {
        m_totalProgress->setMaximum(100);
        m_totalProgress->setValue(progress);
        m_lastRealProgress = progress;
    }
}

void CacheUpdateWidget::downloadProgressChanged(const QApt::DownloadProgress &progress)
{
    if (!m_downloads.contains(progress.uri())) {
        addItem(progress.uri());
        m_downloads.append(progress.uri());
    }
}
